home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 April: Mac OS SDK / Dev.CD Apr 98 SDK1.toast / Development Kits (Disc 1) / Apple Color OneScanner SDK / Scan Image 1.0 / Source / JPEG.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-24  |  10.0 KB  |  465 lines  |  [TEXT/CWIE]

  1. /*************************************************************************************
  2. #
  3. #        JPEG.c
  4. #
  5. #        This segment handles JPEG.
  6. #
  7. #        Author(s):     Michael Marinkovich
  8. #                    Apple Developer Technical Support
  9. #                    marink@apple.com
  10. #
  11. #        Modification History: 
  12. #
  13. #            4/3/96        MWM     Initial coding                     
  14. #
  15. #        Copyright © 1992-96 Apple Computer, Inc., All Rights Reserved
  16. #
  17. #
  18. #        You may incorporate this sample code into your applications without
  19. #        restriction, though the sample code has been provided "AS IS" and the
  20. #        responsibility for its operation is 100% yours.  However, what you are
  21. #        not permitted to do is to redistribute the source as "DSC Sample Code"
  22. #        after having made changes. If you're going to re-distribute the source,
  23. #        we require that you make it clear in the source that the code was
  24. #        descended from Apple Sample Code, but that you've made changes.
  25. #
  26. *************************************************************************************/
  27.  
  28.  
  29. #include <Events.h>
  30. #include <ToolUtils.h>
  31. #include <Gestalt.h>
  32. #include <OSUtils.h>
  33. #include <Palettes.h>
  34.  
  35. #include "App.h"
  36. #include "Proto.h"
  37.  
  38. // data unload buffer size
  39. #define kBufferSize            codecMinimumDataSize
  40.  
  41.  
  42. //----------------------------------------------------------------------
  43. //    Globals
  44. //----------------------------------------------------------------------
  45.  
  46. extern Boolean        gInBackground;
  47.  
  48.  
  49.  
  50. //----------------------------------------------------------------------
  51. //
  52. //    OpenJPEGFile - open a JPEG file with supplied FSSpec.
  53. //                    
  54. //
  55. //----------------------------------------------------------------------
  56.  
  57. CGrafPtr OpenJPEGFile(FSSpec spec, OSErr *theErr)
  58. {
  59.     OSErr            err = noErr;
  60.     Handle            tempHandle;
  61.     Handle            newHandle;
  62.     GWorldPtr        theWorld = nil;
  63.     short            refNum;
  64.     long            fileSize;
  65.     Size            pictSize;
  66.         
  67.     SetCursor(*GetCursor(watchCursor));            // set the cursor to a watch while busy
  68.         
  69.     err = FSpOpenDF(&spec, fsRdWrShPerm, &refNum);
  70.     if ( err == noErr ) 
  71.     {
  72.         err = GetEOF(refNum, &fileSize );
  73.         if ( err == noErr ) 
  74.         {
  75.             tempHandle = NewHandle(fileSize);
  76.             if (tempHandle == nil) 
  77.             {
  78.                 tempHandle = TempNewHandle(fileSize, &err);        // allocate space for picture
  79.             }
  80.             
  81.             if ( err == noErr && tempHandle != nil ) 
  82.             {
  83.                 HLock(tempHandle);
  84.                 err = FSRead(refNum, &fileSize, *tempHandle);    // read in the pict data
  85.                 HUnlock(tempHandle);
  86.             }
  87.         }
  88.         FSClose(refNum);                    // close the file
  89.         
  90.         theWorld = ConvertJPEG(tempHandle);
  91.  
  92.     }    
  93.         
  94.     SetCursor(&qd.arrow );                // set cursor back to arrow
  95.         
  96.     *theErr = err;
  97.         
  98.     return theWorld;
  99.  
  100. }
  101.  
  102.  
  103. //----------------------------------------------------------------------
  104. //
  105. //    ConvertJPEG - Convert JPEG data to a PICT.
  106. //
  107. //
  108. //----------------------------------------------------------------------
  109.  
  110. CGrafPtr ConvertJPEG(Handle image) 
  111. {
  112.     OSErr                    err = noErr;
  113.     GWorldPtr                oldPort;
  114.     GWorldPtr                theWorld;
  115.     GDHandle                oldGD;
  116.     PixMapHandle            thePix;
  117.     ImageDescriptionHandle     desc = nil;
  118.     Rect                    bounds;
  119.  
  120.     GetGWorld(&oldPort, &oldGD);
  121.     
  122.     HLock((Handle)image);
  123.     desc = (ImageDescriptionHandle)NewHandle(sizeof(ImageDescription));
  124.     
  125.     if (desc != nil)
  126.     {
  127.         err = GetJPEGDescription(image, desc, &bounds);
  128.         theWorld = NewJPEGWorld((*desc)->depth, bounds);
  129.         
  130.         if (theWorld != nil) 
  131.         {
  132.             thePix = GetGWorldPixMap(theWorld);
  133.             LockPixels(thePix);
  134.             SetGWorld(theWorld, nil);
  135.             
  136.             err = DecompressImage(*image, desc, thePix, &bounds, &bounds, srcCopy, nil);
  137.                     
  138.             UnlockPixels(thePix);     
  139.                     
  140.         }
  141.         DisposeHandle((Handle)desc);
  142.               
  143.     }
  144.  
  145.     SetGWorld(oldPort, oldGD);
  146.  
  147.     return theWorld;
  148. }
  149.  
  150.  
  151. //----------------------------------------------------------------------
  152. //
  153. //    GetJPEGDescription -
  154. //
  155. //
  156. //----------------------------------------------------------------------
  157.  
  158. OSErr GetJPEGDescription(Handle image, ImageDescriptionHandle desc, Rect *bounds)
  159. {
  160.     OSErr                    err = noErr;
  161.     Fixed                    xRes,yRes;
  162.     long                     i;
  163.     long                     imageSize;
  164.     unsigned char             *buffer;
  165.     char                     JIFF[5];
  166.     short                     w = 0, h = 0;
  167.     short                    units;
  168.     short                    version;
  169.     short                     components;
  170.  
  171.     buffer = (unsigned char *)(*image);
  172.     imageSize = GetHandleSize((Handle)image);
  173.     
  174.     for (i = 0; i < imageSize; i++ ) 
  175.     {
  176.         if (buffer[i] == 0xff) 
  177.         {
  178.             i++;
  179.             if (buffer[i] == 0xc0)         // start of frame header marker
  180.             {        
  181.                 i += 4;
  182.                 h = (buffer[i]<<8) | buffer[i+1];
  183.                 i += 2;
  184.                 w = (buffer[i]<<8) | buffer[i+1];
  185.                 i += 2;
  186.                 if ( w && h )             // make sure we do have something to display
  187.                 {
  188.                     /* now make up the image description */
  189.                     (*desc)->idSize = sizeof(ImageDescription);
  190.                     (*desc)->temporalQuality = 0;
  191.                     (*desc)->spatialQuality = codecNormalQuality;
  192.                     (*desc)->dataSize = imageSize;
  193.                     (*desc)->cType = 'jpeg';
  194.                     (*desc)->version = 0;
  195.                     (*desc)->revisionLevel = 0;
  196.                     (*desc)->vendor = 0;
  197.                     (*desc)->width = w;
  198.                     (*desc)->height = h;
  199.                     (*desc)->clutID = -1;
  200.                     BlockMove("\pPhoto - JPEG",(*desc)->name,13);
  201.                     (*desc)->hRes = xRes;
  202.                     (*desc)->vRes = yRes;
  203.                     
  204.                     components = buffer[i++];
  205.                     
  206.                     switch (components) 
  207.                     {
  208.                         case 3:
  209.                             (*desc)->depth = 32;
  210.                             break;
  211.                             
  212.                         case 1:        
  213.                             (*desc)->depth = 40;
  214.                             break;
  215.                             
  216.                         default:
  217.                             break;
  218.                     }
  219.     
  220.                     SetRect(bounds, 0, 0, w, h);
  221.                     return noErr;
  222.                 }
  223.             }
  224.             if (buffer[i] == 0xe0) // JFIF marker
  225.             {
  226.                 i += 3;
  227.                 JIFF[0] = buffer[i++];
  228.                 JIFF[1] = buffer[i++];
  229.                 JIFF[2] = buffer[i++];
  230.                 JIFF[3] = buffer[i++];
  231.                 JIFF[4] = buffer[i++];
  232.                 
  233.                 // check if we really have the JFIF header
  234.                 if ( JIFF[0] == 'J' && JIFF[1] == 'F'  && JIFF[2] == 'I'  && JIFF[3] == 'F' ) 
  235.                 {
  236.                       version = (buffer[i]<<8) | buffer[i+1];
  237.                       i += 2;
  238.     
  239.                     if ( version < 0x100 )
  240.                     {    
  241.                         err = paramErr;
  242.                         break;     // don't know this
  243.                     }
  244.                     
  245.                     units = buffer[i++];
  246.                     xRes = (buffer[i]<<8) | buffer[i+1];
  247.                       i += 2;
  248.                     yRes = (buffer[i]<<8) | buffer[i+1];
  249.                       i += 2;
  250.         
  251.                     switch ( units ) 
  252.                     {
  253.                         case 0:            // no res, just aspect ratio
  254.                             xRes = FixMul(72L << 16, xRes << 16);
  255.                             yRes = FixMul(72L << 16, yRes << 16);
  256.                             break;
  257.                             
  258.                         case 1:            // dots per inch
  259.                             xRes = xRes << 16;
  260.                             yRes = yRes << 16;
  261.                             break;
  262.                             
  263.                         case 2:            // dots per centimeter (we convert to dpi )
  264.                             xRes = FixMul(0x28a3d, xRes << 16);
  265.                             yRes = FixMul(0x28a3d, xRes << 16);
  266.                             break;    
  267.                             
  268.                         default:
  269.                             break;
  270.                     }
  271.                 }
  272.             }
  273.         }        
  274.     }
  275.  
  276.     return err;
  277. }
  278.  
  279.  
  280. //----------------------------------------------------------------------
  281. //
  282. //    NewJPEGWorld -
  283. //
  284. //
  285. //----------------------------------------------------------------------
  286.  
  287. GWorldPtr NewJPEGWorld(short depth, Rect theRect)
  288. {
  289.     OSErr            err;
  290.     GWorldPtr        theWorld = nil;
  291.     GWorldPtr        oldPort;
  292.     PixMapHandle    thePix;
  293.     CTabHandle        cTab = nil;
  294.     GDHandle        oldGD;
  295.     
  296.     GetGWorld(&oldPort,&oldGD);
  297.  
  298.     // if depth is greater than 32 then the 
  299.     // image is grayscale
  300.     if (depth > 32) 
  301.     {
  302.         cTab = GetCTable(depth);
  303.         depth = depth - 32;
  304.     }
  305.     
  306.     err = NewGWorld(&theWorld, depth, &theRect, cTab, nil, 0L);    // try our heap
  307.     
  308.     if (err != noErr)
  309.         err = NewGWorld(&theWorld, depth, 
  310.                         &theRect, cTab, nil, useTempMem);    // else try temp
  311.  
  312.     if (err == noErr && theWorld != nil) 
  313.     {
  314.         thePix = GetGWorldPixMap(theWorld);
  315.                 
  316.         if (LockPixels(thePix)) 
  317.         {
  318.             SetGWorld(theWorld, nil);
  319.             EraseRect(&theRect);
  320.             
  321.             UnlockPixels(thePix);
  322.         }
  323.     }
  324.     
  325.     SetGWorld(oldPort, oldGD);    
  326.  
  327.     return theWorld;
  328.     
  329. }
  330.  
  331.  
  332. //----------------------------------------------------------------------
  333. //
  334. //    DoSaveJPEG -
  335. //
  336. //
  337. //----------------------------------------------------------------------
  338.  
  339. OSErr SaveJPEGFile(StandardFileReply reply, WindowRef window)
  340. {
  341.     OSErr                        err = noErr;
  342.     ImageDescriptionHandle         desc;
  343.     Handle                        data;
  344.     Str255                        str;
  345.     Rect                        srcRect;
  346.     GWorldPtr                    theWorld;
  347.     PixMapHandle                thePix;
  348.     CTabHandle                    cTab = nil;
  349.     ICMFlushProcRecord            flushProc;
  350.     long                        size;
  351.     long                        dataSize;
  352.     short                        refNum;
  353.     short                        depth;
  354.     Str255                         title;
  355.     DocHnd                        doc;
  356.     
  357.  
  358.     GetWTitle(window, title);
  359.     
  360.     doc = (DocHnd)GetWRefCon(window);
  361.     
  362.     if (reply.sfGood && doc != nil)
  363.     {
  364.         desc = (ImageDescriptionHandle)NewHandle(sizeof(ImageDescription));
  365.  
  366.         theWorld = (**doc).world;
  367.         
  368.         if (theWorld != nil && desc != nil) 
  369.         {            
  370.             srcRect = theWorld->portRect;
  371.             thePix = GetGWorldPixMap(theWorld);
  372.             
  373.             if (LockPixels(thePix)) 
  374.             {    
  375.                 depth = (**thePix).pixelSize;
  376.                 if (depth < 16)
  377.                     cTab = (**thePix).pmTable;
  378.     
  379.                 data = NewHandle(kBufferSize);
  380.                 err = MemError();
  381.                 
  382.                 if (data != nil && err == noErr) 
  383.                 {
  384.                     HLock(data);
  385.                                                                  
  386.                     if (reply.sfReplacing ) 
  387.                         err = FSpDelete(&reply.sfFile);
  388.                 
  389.                     err = FSpCreate(&reply.sfFile, 'JVWR', kJPEGType, reply.sfScript);
  390.                     
  391.                     if (err == noErr)
  392.                         err = FSpOpenDF(&reply.sfFile,fsRdWrPerm, &refNum);
  393.                         
  394.                     if (err == noErr)
  395.                         err = SetFPos(refNum, fsFromStart , 0);
  396.                         
  397.                     if (err == noErr)
  398.                     {
  399.                         flushProc.flushProc = NewICMFlushProc(DataUnloadProc);
  400.                         flushProc.flushRefCon = refNum;
  401.  
  402.                         err = FCompressImage(thePix, &srcRect, depth,
  403.                                              codecNormalQuality, 'jpeg',
  404.                                              bestCompressionCodec, cTab,
  405.                                              codecFlagWasCompressed, kBufferSize, 
  406.                                              &flushProc, nil, desc, *data);
  407.                     }
  408.                         
  409.                     if (err == noErr)
  410.                         err = SetFPos(refNum, fsFromStart, (**desc).dataSize);
  411.  
  412.                     if (err == noErr)
  413.                         err = SetEOF(refNum, (**desc).dataSize);
  414.                                  
  415.                     if (err == noErr)        
  416.                         err = FSClose( refNum );
  417.                     
  418.                     HUnlock(data);
  419.                     DisposeHandle(data);
  420.                     
  421.                     DisposeRoutineDescriptor(flushProc.flushProc);
  422.                     
  423.                     if (cTab != nil)
  424.                         DisposeCTable(cTab);
  425.                 }
  426.  
  427.             }
  428.             
  429.             UnlockPixels(thePix);
  430.         
  431.         }
  432.         DisposeHandle((Handle)desc);
  433.     }
  434.     else
  435.         err = dsMemFullErr;
  436.     
  437.     return err;
  438.     
  439. }            
  440.     
  441.     
  442.  
  443. //----------------------------------------------------------------------
  444. //
  445. //    DataUnloadProc -
  446. //
  447. //
  448. //----------------------------------------------------------------------
  449.  
  450. pascal OSErr DataUnloadProc(Ptr data, long bytesNeeded, long refCon)
  451. {
  452.     OSErr        err;
  453.     
  454.     if (data == nil)
  455.     {
  456.         err = SetFPos(refCon, fsCurPerm, bytesNeeded);
  457.     }
  458.     else
  459.     {    
  460.         err = FSWrite(refCon, &bytesNeeded, data);
  461.     }
  462.     
  463.     return err;
  464.     
  465. }